package com.flyco.modules.stm.controller;

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.flyco.common.exception.FlycoException;
import com.flyco.common.util.DateUtils;
import com.flyco.modules.oms.entity.OmsOrder;
import com.flyco.modules.oms.entity.OmsOrderItem;
import com.flyco.modules.oms.mapper.OmsOrderItemMapper;
import com.flyco.modules.oms.service.IOmsOrderService;
import com.flyco.modules.pms.entity.PmsProduct;
import com.flyco.modules.pms.entity.PmsSkuStock;
import com.flyco.modules.pms.mapper.PmsSkuStockMapper;
import com.flyco.modules.pms.service.IPmsProductService;
import com.flyco.modules.pms.service.IPmsSkuStockService;
import com.flyco.modules.stm.entity.*;
import com.flyco.modules.stm.mapper.*;
import com.flyco.modules.stm.model.StmStockInoutExcel;
import com.flyco.modules.stm.service.*;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.shiro.SecurityUtils;
import com.flyco.poi.excel.ExcelImportUtil;
import com.flyco.poi.excel.def.NormalExcelConstants;
import com.flyco.poi.excel.entity.ExportParams;
import com.flyco.poi.excel.entity.ImportParams;
import com.flyco.poi.excel.view.EntityExcelView;
import com.flyco.common.system.vo.LoginUser;
import com.flyco.common.api.vo.Result;
import com.flyco.common.system.query.QueryGenerator;
import com.flyco.modules.stm.vo.StmStockInoutPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.flyco.common.aspect.annotation.AutoLog;

/**
 * @Description: 总仓出入库单
 * @Author: flyco
 * @Date: 2020-12-03
 * @Version: V1.0
 */
@Api(tags = "总仓出入库单")
@RestController
@RequestMapping("/f/stm/stmStockInout")
@Slf4j
public class StmStockInoutController {
    @Autowired
    private IStmStockInoutService stmStockInoutService;
    @Autowired
    private IStmBizInoutRelationService stmBizInoutRelationService;
    @Autowired
    private IStmStockInoutItemService stmStockInoutItemService;
    @Autowired
    private IStmStoreInfoService stmStoreInfoService;
    @Autowired
    private IPmsProductService pmsProductService;
    @Autowired
    private IStmStockService stmStockService;

    @Autowired
    private StmBizInoutRelationMapper stmBizInoutRelationMapper;

    @Autowired
    private StmStockInoutRecordMapper stmStockInoutRecordMapper;

    @Autowired
    private OmsOrderItemMapper omsOrderItemMapper;

    @Autowired
    private PmsBoxTraceRecordMapper pmsBoxTraceRecordMapper;

    @Autowired
    private StmStockRecordMapper stmStockRecordMapper;

    @Autowired
    private StmStockInoutItemMapper stmStockInoutItemMapper;
    @Autowired
    private IOmsOrderService omsOrderService;
    @Autowired
    private IStmOrderItemService omsOrderItemService;
    @Autowired
    private IPmsSkuStockService pmsSkuStockService;
    @Autowired
    private PmsSkuStockMapper pmsSkuStockMapper;
    @Autowired
    private IPmsBoxTraceService pmsBoxTraceService;

    /**
     * 分页列表查询
     *
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AutoLog(value = "总仓出入库单-分页列表查询")
    @ApiOperation(value = "总仓出入库单-分页列表查询", notes = "总仓出入库单-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(StmBizInoutRelation stmBizInoutRelation,
                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                   @RequestParam("bizType") Integer bizType,
                                   HttpServletRequest req) {
        QueryWrapper<StmBizInoutRelation> queryWrapper = QueryGenerator.initQueryWrapper(stmBizInoutRelation, req.getParameterMap());
        queryWrapper.eq("store_id", 0);
        queryWrapper.eq("cancel_flag",0);
        if (Objects.equals(1, bizType)) {
            //没有发货单的出库单
            queryWrapper.isNull("send_order_id");
        }
        else{
            //有发货单的出库单
            queryWrapper.isNotNull("send_order_id");
        }
        if (stmBizInoutRelation.getStartTime() != null && stmBizInoutRelation.getEndTime() != null) {
            queryWrapper.between("create_time", stmBizInoutRelation.getStartTime(), stmBizInoutRelation.getEndTime());
        }

        Page<StmBizInoutRelation> page = new Page<StmBizInoutRelation>(pageNo, pageSize);
        IPage<StmBizInoutRelation> pageList = stmBizInoutRelationService.page(page, queryWrapper);
        return Result.ok(pageList);
    }

    /**
     * 分页列表查询
     *
     * @param
     * @param pageNo
     * @param pageSize
     * @return
     */
    @AutoLog(value = "出库记录-分页列表查询")
    @ApiOperation(value = "出库记录-分页列表查询", notes = "出库记录-分页列表查询")
    @GetMapping(value = "/queryItemlistByRelationId")
    public Result<?> queryItemlistByRelationId(StmBizInoutRelation stmBizInoutRelation,
                                               @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                               @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize
    ) {
        List<StmStockInoutItem> stmStockInoutItems = stmStockInoutItemMapper.queryItemlistByRelationId(stmBizInoutRelation.getId());
        Set<Long> productIds = stmStockInoutItems.stream().map(q -> q.getProductId()).collect(Collectors.toSet());
        QueryWrapper<PmsProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", productIds);
        List<PmsProduct> products = pmsProductService.list(queryWrapper);
        Map<Long, String> productsMap = new HashMap<>();
        products.forEach(pmsProduct -> productsMap.put(pmsProduct.getId(), pmsProduct.getSkuCode()));
        stmStockInoutItems.forEach(stmStockInoutItem -> stmStockInoutItem.setSkuCode(productsMap.get(stmStockInoutItem.getProductId())));
        Page<StmStockInoutItem> page = new Page<StmStockInoutItem>(pageNo, pageSize);
        page.setRecords(stmStockInoutItems);
        page.setTotal(stmStockInoutItems.size());
        return Result.ok(page);
    }

    /**
     * 分页列表查询
     *
     * @param
     * @param pageNo
     * @param pageSize
     * @return
     */
    @AutoLog(value = "出库明细-分页列表查询")
    @ApiOperation(value = "出库明细-分页列表查询", notes = "出库明细-分页列表查询")
    @GetMapping(value = "/queryOrderItemlistByRelationId")
    public Result<?> queryOrderItemlistByRelationId(StmBizInoutRelation stmBizInoutRelation,
                                                    @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                    @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize
    ) {
        stmBizInoutRelation = stmBizInoutRelationService.getById(stmBizInoutRelation.getId());
        QueryWrapper<OmsOrderItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", stmBizInoutRelation.getOrderId());
        Page<OmsOrderItem> page = new Page<OmsOrderItem>(pageNo, pageSize);
        IPage<OmsOrderItem> pageList = omsOrderItemService.page(page, queryWrapper);
        return Result.ok(page);
    }

    /**
     * 通过id取消订单
     *
     * @param
     * @return
     */
    @AutoLog(value = "作废入库单")
    @PutMapping(value = "/cancel")
    public Result<?> cancel(@RequestBody StmBizInoutRelation stmBizInoutRelation) {
        stmBizInoutRelation = stmBizInoutRelationService.getById(stmBizInoutRelation.getId());
        if (stmBizInoutRelation.getStatus() != 1) {
            return Result.error("状态不对，无法作废!");
        }
        stmBizInoutRelation.setStatus(4);
        stmBizInoutRelationService.updateById(stmBizInoutRelation);
        return Result.ok("取消成功!");
    }

    /**
     * 添加
     *
     * @param stmStockInoutPage
     * @return
     */
    @AutoLog(value = "总仓入库单-添加")
    @ApiOperation(value = "总仓入库单-添加", notes = "总仓入库单-添加")
    @PostMapping(value = "/addStmStockIn")
    public Result<?> addStmStockIn(@RequestBody StmStockInoutPage stmStockInoutPage) {

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<StmStockInoutItem> stmStockInoutItems = stmStockInoutPage.getStmStockInoutItemList();
        Set<String> skuCodes = stmStockInoutItems.stream().map(q -> q.getSkuCode()).collect(Collectors.toSet());
        LambdaQueryWrapper<PmsProduct> query = new LambdaQueryWrapper<>();
        query.in(PmsProduct::getSkuCode, skuCodes);
        List<PmsProduct> products = pmsProductService.list(query);
        Map<String, PmsProduct> productMap = new HashMap<>();
        products.forEach(a -> {
            productMap.put(a.getSkuCode(), a);
        });
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setId(DateUtils.yyyymmddhhmmss.get().format(new Date()) + Math.round(Math.random() * 10000));
        omsOrder.setPartnerId(0l);
        omsOrder.setStoreId(0l);
        omsOrder.setMemberId(0l);
        omsOrder.setStatus(3);
        omsOrder.setProductStatus(4);
        omsOrder.setPayStatus(4);
        omsOrder.setReceiverName(sysUser.getRealname());
        omsOrder.setReceiverPhone(sysUser.getPhone());
        omsOrderService.save(omsOrder);
        List<OmsOrderItem> omsOrderItems = new ArrayList<>();
        stmStockInoutItems.forEach(a -> {
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            omsOrderItem.setProductSkuCode(a.getSkuCode());
            if (productMap.get(a.getSkuCode()) != null) {
                omsOrderItem.setProductName(productMap.get(a.getSkuCode()).getName());
                omsOrderItem.setProductSn(productMap.get(a.getSkuCode()).getProductSn());
                omsOrderItem.setProductId(productMap.get(a.getSkuCode()).getId());
                LambdaQueryWrapper<PmsSkuStock> queryWrapper = new LambdaQueryWrapper<PmsSkuStock>()
                        .eq(PmsSkuStock::getStoreId, 0l)
                        .eq(PmsSkuStock::getProductId, omsOrderItem.getProductId());
                PmsSkuStock pmsSkuStock = pmsSkuStockService.getOne(queryWrapper);
                omsOrderItem.setProductSkuId(pmsSkuStock.getId());
            }
            omsOrderItem.setProductQuantity(a.getProductQty());
            omsOrderItem.setSendQty(new BigDecimal(a.getProductQty()));
            omsOrderItem.setOrderId(omsOrder.getId());

            omsOrderItems.add(omsOrderItem);
        });
        omsOrderItemService.saveBatch(omsOrderItems);
        StmBizInoutRelation stmBizInoutRelation = new StmBizInoutRelation();
        stmBizInoutRelation.setPartnerId(0l);
        stmBizInoutRelation.setStoreName("总仓");
        stmBizInoutRelation.setStatus(1);
        stmBizInoutRelation.setStoreId(0l);
        stmBizInoutRelation.setSourceType("RECEIPT_TYPE_PACKAGE");
        stmBizInoutRelation.setStockBizType("STOCK_IN_TYPE_PACKAGE");
        stmBizInoutRelation.setSourceStoreId(0l);
        stmBizInoutRelation.setNote(stmStockInoutPage.getContent());
        stmBizInoutRelation.setSourceStoreName("总仓");
        stmBizInoutRelation.setCreateBy(sysUser.getRealname());
        stmBizInoutRelation.setType("STOCK_IN");
        stmBizInoutRelation.setCreateTime(new Date());
        stmBizInoutRelation.setOrderId(omsOrder.getId());
        stmBizInoutRelation.setSourceId(Long.valueOf(omsOrder.getId()));
        stmBizInoutRelationService.save(stmBizInoutRelation);
        return Result.ok("添加成功！");
    }

    /**
     * 添加
     *
     * @param stmStockInoutPage
     * @return
     */
    @AutoLog(value = "总仓出入库单-添加")
    @ApiOperation(value = "总仓出入库单-添加", notes = "总仓出入库单-添加")
    @PostMapping(value = "/add")
    public Result<?> add(@RequestBody StmStockInoutPage stmStockInoutPage) {
        StmStockInout stmStockInout = new StmStockInout();
        BeanUtils.copyProperties(stmStockInoutPage, stmStockInout);
        stmStockInoutService.save(stmStockInout);
        return Result.ok("添加成功！");
    }

    /**
     * 编辑
     *
     * @param stmStockInoutPage
     * @return
     */
    @AutoLog(value = "总仓出入库单-编辑")
    @ApiOperation(value = "总仓出入库单-", notes = "总仓出入库单-编辑")
    @PutMapping(value = "/edit")
    public Result<?> edit(@RequestBody StmStockInoutPage stmStockInoutPage) {
        StmStockInout stmStockInout = new StmStockInout();
        BeanUtils.copyProperties(stmStockInoutPage, stmStockInout);
        stmStockInoutService.updateById(stmStockInout);
        return Result.ok("编辑成功!");
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "总仓出入库单-通过id删除")
    @ApiOperation(value = "总仓出入库单-通过id删除", notes = "总仓出入库单-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name = "id", required = true) Long id) {
        stmStockInoutService.delMain(id);
        return Result.ok("删除成功!");
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "总仓出入库单-批量删除")
    @ApiOperation(value = "总仓出入库单-批量删除", notes = "总仓出入库单-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        this.stmStockInoutService.removeByIds(Arrays.asList(ids.split(",")));
        return Result.ok("批量删除成功！");
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @AutoLog(value = "总仓出入库单-通过id查询")
    @ApiOperation(value = "总仓出入库单-通过id查询", notes = "总仓出入库单-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<?> queryById(@RequestParam(name = "id", required = true) Long id) {
        StmStockInout stmStockInout = stmStockInoutService.getById(id);
        return Result.ok(stmStockInout);
    }


    //===========================以下是子表信息操作相关API====================================

    /**
     * 通过主表id查询总仓出入库明细
     *
     * @param stmStockInoutItem
     * @return
     */
    @AutoLog(value = "总仓出入库明细-通过主表id查询")
    @ApiOperation(value = "总仓出入库明细-通过主表id查询", notes = "总仓出入库明细-通过主表id查询")
    @GetMapping(value = "/listStmStockInoutItemByMainId")
    public Result<?> listStmStockInoutItemByMainId(StmStockInoutItem stmStockInoutItem,
                                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                   HttpServletRequest req) {
        if (stmStockInoutItem.getInoutId() != null) {
            QueryWrapper<StmStockInoutItem> queryWrapper = QueryGenerator.initQueryWrapper(stmStockInoutItem, req.getParameterMap());
            Page<StmStockInoutItem> page = new Page<StmStockInoutItem>(pageNo, pageSize);
            IPage<StmStockInoutItem> pageList = stmStockInoutItemService.page(page, queryWrapper);
            return Result.ok(pageList);
        } else {
            return Result.error("请选择入库单");
        }
    }


    /**
     * 导出excel
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, StmBizInoutRelation stmBizInoutRelation) {

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        List<StmStockInoutExcel> stockInoutExcels = stmBizInoutRelationService.getInoutItemRecord(stmBizInoutRelation.getId());

        //Step.3 调用AutoPoi导出Excel
        ModelAndView mv = new ModelAndView(new EntityExcelView());
        mv.addObject(NormalExcelConstants.FILE_NAME, "出库单报表");
        mv.addObject(NormalExcelConstants.CLASS, StmStockInoutExcel.class);
        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("出库单报表", "导出人:" + sysUser.getRealname(), "出库单报表"));
        mv.addObject(NormalExcelConstants.DATA_LIST, stockInoutExcels);
        return mv;
    }


    @RequestMapping(value = "/download")
    public void download(HttpServletRequest req, HttpServletResponse res) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {

            inputStream = this.getClass().getResourceAsStream("/templates/入库明细模板.xlsx");
            outputStream = res.getOutputStream();
            int temp = 0;
            while ((temp = inputStream.read()) != -1) {
                outputStream.write(temp);
            }
            res.setContentType("application/force-download");// 设置强制下载不打开
            res.addHeader("Content-Disposition", "attachment;fileName=" + new String("入库明细模板.xlsx".getBytes("UTF-8"), "iso-8859-1"));
            res.setHeader("content-type", "text/html;charset=UTF-8");
            res.setCharacterEncoding("UTF-8");
        } catch (Exception e) {
            log.error("", e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return;
    }

    /**
     * 通过excel导入数据
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        Long bizInoutId = Long.valueOf(request.getParameter("id"));
        Integer type = Integer.valueOf(request.getParameter("type"));
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<InoutItem> list = ExcelImportUtil.importExcel(file.getInputStream(), InoutItem.class, params);
                //将excel的数据组装成按照skucode分组的数据格式，方便后续处理
                Map<String, Set<String>> skucodemap = new HashMap<>();
                list.forEach(a -> {
                    if (skucodemap.get(a.getSkuCode()) == null) {
                        Set<String> boxCodeList = new HashSet<String>();
                        boxCodeList.add(a.getBoxCode());
                        skucodemap.put(a.getSkuCode(), boxCodeList);
                    } else {
                        Set<String> boxCodeList = skucodemap.get(a.getSkuCode());
                        boxCodeList.add(a.getBoxCode());
                    }
                });
                list = new ArrayList<>();
                for (String key : skucodemap.keySet()) {
                    InoutItem inoutItem = new InoutItem();
                    inoutItem.setSkuCode(key);
                    inoutItem.setBoxCodeList(skucodemap.get(key));
                    list.add(inoutItem);
                }
                InoutDTO inoutDTO = new InoutDTO();
                inoutDTO.setInoutItemList(list);
                inoutDTO.setStockInoutId(bizInoutId);
                inout(bizInoutId, type == 1 ? InoutType.STOCK_IN : InoutType.STOCK_OUT, inoutDTO);
                return Result.ok("文件导入成功！数据行数:" + list.size());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败:" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.ok("文件导入失败！");
    }

    private void inout(Long bizInoutId, InoutType inoutType, InoutDTO inoutDTO) throws Exception {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String realName = sysUser.getRealname();
        Long partnerId = sysUser.getPartnerId();
        //出入库关联表
        StmBizInoutRelation stmBizInoutRelation = stmBizInoutRelationMapper.selectById(bizInoutId);
        if (stmBizInoutRelation == null
                || !Objects.equals(partnerId, stmBizInoutRelation.getPartnerId())) {
            throw new FlycoException("数据不存在");
        }
        if (!Objects.equals(stmBizInoutRelation.getType(), inoutType.name())) {
            throw new FlycoException("出入库类型不正确");
        }
        if (Objects.equals(stmBizInoutRelation.getStatus(), 7)) {
            throw new FlycoException("当前状态已完成，无法操作");
        }
        List<StmStockInoutItem> recordList = new ArrayList<>();
        Long storeId = 0l;
        int status;

        //更新订单数据
        status = updateOrderStock(stmBizInoutRelation.getOrderId(), inoutType, realName, inoutDTO.getInoutItemList(), recordList);


        //记录出入库记录 stock_inout_record 和库存记录流水，变更库存
        saveInoutRecord(partnerId, storeId, stmBizInoutRelation, realName, recordList);

        //记录箱码出库轨迹
        if (inoutType == InoutType.STOCK_OUT) {
            saveBoxRecord(realName, stmBizInoutRelation, inoutDTO.getInoutItemList(), recordList);
        }

        //更新出入库关联表状态
        StmBizInoutRelation bizInoutRelation = new StmBizInoutRelation();
        bizInoutRelation.setId(bizInoutId);
        bizInoutRelation.setStatus(status);
        bizInoutRelation.setUpdateBy(realName);
        bizInoutRelation.setUpdateTime(new Date());
        stmBizInoutRelationMapper.updateById(bizInoutRelation);


        return;
    }

    private void saveBoxRecord(String realName, StmBizInoutRelation stmBizInoutRelation, List<InoutItem> inoutItemList, List<StmStockInoutItem> recordList) {
        Date now = new Date();
        //key：箱码，value：orderItemId
        Map<String, Long> map = new HashMap<>();
        inoutItemList.forEach(one -> one.getBoxCodeList().forEach(boxCode -> map.put(boxCode, one.getId())));

        recordList.forEach(one -> {
            one.getBoxCodeList().forEach(box -> {
                PmsBoxTraceRecord pmsBoxTraceRecord = new PmsBoxTraceRecord();
                pmsBoxTraceRecord.setBoxCode(box);
                pmsBoxTraceRecord.setBizInoutRelationId(stmBizInoutRelation.getId());
                pmsBoxTraceRecord.setProductId(one.getProductId());
                pmsBoxTraceRecord.setProductSn(one.getProductSn());
                pmsBoxTraceRecord.setProductName(one.getProductName());
                Long orderItemId = map.get(box);
                if (orderItemId != null) {
                    pmsBoxTraceRecord.setOrderItemId(orderItemId);
                }
                pmsBoxTraceRecord.setCreateTime(now);
                pmsBoxTraceRecord.setCreateBy(realName);
                pmsBoxTraceRecordMapper.insert(pmsBoxTraceRecord);
            });
        });
    }

    private void saveInoutRecord(Long partnerId, Long storeId, StmBizInoutRelation stmBizInoutRelation, String realName, List<StmStockInoutItem> recordList) {
        Date now = new Date();

        //记录出入库记录
        StmStockInoutRecord stockInoutRecord = new StmStockInoutRecord();
        stockInoutRecord.setPartnerId(stmBizInoutRelation.getPartnerId());
        stockInoutRecord.setBizInoutRelationId(stmBizInoutRelation.getId());
        stockInoutRecord.setCreateBy(realName);
        stockInoutRecord.setCreateTime(now);
        stmStockInoutRecordMapper.insert(stockInoutRecord);

        recordList.forEach(one ->
        {
            one.setInoutId(stockInoutRecord.getId());
            stmStockInoutItemMapper.insert(one);
        });

        Map<Long, StmStockInoutItem> map = recordList.stream().collect(Collectors.toMap(StmStockInoutItem::getProductId, a -> a));

        LambdaQueryWrapper<PmsSkuStock> queryWrapper = new LambdaQueryWrapper();
        //库存增减商品
        List<Long> productIds = recordList.stream().map(StmStockInoutItem::getProductId).collect(Collectors.toList());
        queryWrapper.eq(PmsSkuStock::getStoreId, 0l).in(PmsSkuStock::getProductId, productIds);
        List<PmsSkuStock> pmsSkuStockList = pmsSkuStockMapper.selectList(queryWrapper);


        List<PmsSkuStock> collect = pmsSkuStockList.stream().map(one -> {
            PmsSkuStock pmsSkuStock = new PmsSkuStock();
            pmsSkuStock.setId(one.getId());
            StmStockInoutItem record = map.get(one.getProductId());
            if (record == null) {
                throw new FlycoException("库存内容不存在");
            }
            int count = record.getInoutQty();
            if (Objects.equals(stmBizInoutRelation.getType(), "STOCK_OUT")) {
                count = -1 * count;
            }
            pmsSkuStock.setStock(count);
            return pmsSkuStock;
        }).collect(Collectors.toList());
        pmsSkuStockMapper.updateSkuStock(collect);

        //记录库存流水记录
        pmsSkuStockList.forEach(one -> {
            StmStockRecord stmStockRecord = new StmStockRecord();
            stmStockRecord.setStoreId(one.getStoreId());

            StmStockInoutItem record = map.get(one.getProductId());
            stmStockRecord.setProductSn(record.getProductSn());
            stmStockRecord.setProductId(one.getProductId());
            stmStockRecord.setSkuCode(one.getSkuCode());
            stmStockRecord.setStockId(one.getId());
            stmStockRecord.setQuantity(record.getInoutQty());
            stmStockRecord.setSourceType(stmBizInoutRelation.getSourceType());
            stmStockRecord.setSourceId(stmBizInoutRelation.getSourceId() + "");
            stmStockRecord.setChangeReason(SourceType.getTitle(stmBizInoutRelation.getSourceType()));
            stmStockRecord.setVersion(0);
            stmStockRecord.setCreateBy(realName);
            stmStockRecord.setCreateTime(now);

            stmStockRecord.setOldStock(one.getStock());
            stmStockRecord.setInoutType(stmBizInoutRelation.getType());
            stmStockRecord.setStockType("STOCK_TYPE_GOODS");
            stmStockRecord.setBizType(stmBizInoutRelation.getStockBizType());

            stmStockRecordMapper.insert(stmStockRecord);
        });
    }

    public int updateOrderStock(String orderId, InoutType inoutType, String realName, List<InoutItem> inoutItemList, List<StmStockInoutItem> recordList) {
        int status = 7;
        OmsOrder omsOrder = omsOrderService.getById(orderId);
        if (omsOrder == null || omsOrder.getDeleteStatus() != 0) {
            throw new FlycoException("订单不存在");
        }
        if (omsOrder.getStatus() < 1 || omsOrder.getPayStatus() != 4 || omsOrder.getProductStatus() < 3) {
            throw new FlycoException("订单状态不正确!");
        }
        List<OmsOrderItem> omsOrderItemList = omsOrderItemService.selectByMainId(orderId);
        Map<String, OmsOrderItem> itemMap = omsOrderItemList.stream().collect(Collectors.toMap(OmsOrderItem::getProductSkuCode, a -> a));

        //判断传入的id是否正确，设置出入库记录明细
        List<StmStockInoutItem> collect = inoutItemList.stream().map(one -> {
            OmsOrderItem omsOrderItem = itemMap.get(one.getSkuCode());
            if (omsOrderItem == null) {
                throw new FlycoException("数据错误，订单明细不存在：skuCode=" + one.getSkuCode());
            }
            if (one.getBoxCodeList() == null || one.getBoxCodeList().size() != omsOrderItem.getProductQuantity()) {
                throw new FlycoException("商品数量和导入的箱码数量不一致：skuCode=" + one.getSkuCode());
            }

            //把商品明细id设置一下
            one.setId(omsOrderItem.getId());

            StmStockInoutItem stockInoutItemRecord = new StmStockInoutItem();
            stockInoutItemRecord.setInoutQty(omsOrderItem.getProductQuantity());
            stockInoutItemRecord.setProductId(omsOrderItem.getProductId());
            stockInoutItemRecord.setProductSn(omsOrderItem.getProductSn());
            stockInoutItemRecord.setProductName(omsOrderItem.getProductName());
            stockInoutItemRecord.setStockType("STOCK_TYPE_GOODS");
            //设置该商品对应的箱码
            stockInoutItemRecord.setBoxCodeList(new ArrayList<>(one.getBoxCodeList()));
            return stockInoutItemRecord;
        }).collect(Collectors.toList());

        recordList.addAll(collect);


        List<InoutItem> inoutItems = inoutItemList.stream().map(one -> {
            OmsOrderItem omsOrderItem = itemMap.get(one.getSkuCode());
            if (omsOrderItem == null) {
                throw new FlycoException("数据错误，订单明细不存在：skuCode=" + one.getSkuCode());
            }
            if (one.getBoxCodeList() == null || one.getBoxCodeList().size() != omsOrderItem.getProductQuantity()) {
                throw new FlycoException("商品数量和导入的箱码数量不一致：skuCode=" + one.getSkuCode());
            }
            InoutItem inoutItem = new InoutItem();
            inoutItem.setInoutQty(omsOrderItem.getProductQuantity());
            inoutItem.setId(omsOrderItem.getId());
            inoutItem.setBoxCode(one.getBoxCode());
            inoutItem.setBoxCodeList(one.getBoxCodeList());
            inoutItem.setSkuCode(one.getSkuCode());
            return inoutItem;
        }).collect(Collectors.toList());


        //更新订单明细收发货数量
        if (inoutType == InoutType.STOCK_IN) {
            return stockInProcess(omsOrder, inoutItems);
        } else {
            return stockOutProcess(omsOrder, inoutItems, omsOrderItemList);
        }
    }

    public int stockInProcess(OmsOrder omsOrder, List<InoutItem> inoutItemList) {
        int status = 7;
        int cnt = omsOrderItemMapper.updateOrderItemReceiveQty(inoutItemList);
        if (cnt <= 0) {
            throw new FlycoException("更新失败");
        }

        //如果存在多次部分收货，要等待全部收货完成，这里才修改订单状态
        if (status == 7) {
            //收货时的状态检查和订单表状态更新
            //status=3,pay_status=4，product_status=4才能入库
            if (omsOrder.getStatus() != 3 || omsOrder.getPayStatus() != 4 || omsOrder.getProductStatus() != 4) {
                throw new FlycoException("订单状态不正确");
            }
        }

        return status;
    }

    int stockOutProcess(OmsOrder omsOrder, List<InoutItem> inoutItemList, List<OmsOrderItem> omsOrderItemList) {
        int status = 7;
        Date date = new Date();
        int cnt = omsOrderItemMapper.updateOrderItemSendQty(inoutItemList);
        if (cnt <= 0) {
            throw new FlycoException("更新失败");
        }
        //如果存在多次部分发货，要等待全部发货完成，这里才修改订单状态
        if (status == 7) {
            //status=1,pay_status=4，product_status=3才能出库
            if (omsOrder.getStatus() != 1 || omsOrder.getPayStatus() != 4 || omsOrder.getProductStatus() != 3) {
                throw new FlycoException("订单状态不正确");
            }
            //修改订单状态
            OmsOrder order = new OmsOrder();
            order.setStatus(2);
            order.setProductStatus(4);
            order.setUpdateTime(date);
            order.setDeliveryTime(date);
            Boolean b = omsOrderService.update(omsOrder, Wrappers.lambdaUpdate(OmsOrder.class)
                    .eq(OmsOrder::getId, omsOrder.getId())
                    .eq(OmsOrder::getStatus, 1).eq(OmsOrder::getPayStatus, 4).eq(OmsOrder::getProductStatus, 3));
            if (!b) {
                throw new FlycoException("订单状态修改失败，请稍后重试");
            }

        } else {
            //部分发货，这里先不修改订单状态

        }
        //订单出库，这里storeId=0
        LambdaQueryWrapper<PmsSkuStock> queryWrapper = new LambdaQueryWrapper<PmsSkuStock>();
        queryWrapper.eq(PmsSkuStock::getStoreId, 0l).in(PmsSkuStock::getId, omsOrderItemList.stream().map(OmsOrderItem::getProductSkuId).collect(Collectors.toList()));
        Map<Long, Long> map = pmsSkuStockService.list(queryWrapper).stream().collect(Collectors.toMap(PmsSkuStock::getId, PmsSkuStock::getVersion));
        //根据页面传入的出库数量，修改解锁库存
        for (OmsOrderItem omsOrderItem : omsOrderItemList) {
            Long version = map.get(omsOrderItem.getProductSkuId());
            if (version == null) {
                throw new FlycoException(omsOrderItem.getProductName() + "库存记录不存在");
            }
            int count = pmsSkuStockMapper.releaseLockStock(omsOrderItem.getProductSkuId(), omsOrderItem.getProductQuantity(), version);
            if (count < 1) {
                throw new FlycoException(omsOrderItem.getProductName() + "库存解锁失败，请稍后重试!");
            }
        }

        //箱码溯源表数据写入
        StmStoreInfo storeInfo = stmStoreInfoService.getById("0-0");
        if (storeInfo == null) {
            throw new FlycoException("总仓数据维护错误");
        }

        PmsBoxTrace PmsBoxTrace = createPmsBoxTrace(storeInfo, omsOrder, date);
        for (InoutItem inoutItem : inoutItemList) {
            inoutItem.getBoxCodeList().forEach(boxCode -> {
                try {
                    //每个箱码一条记录
                    PmsBoxTrace.setBoxCode(boxCode);
                    pmsBoxTraceService.save(PmsBoxTrace);
                } catch (Exception e) {
                    throw new FlycoException(boxCode + "重复出库，请检查");
                }
            });
        }

        return status;
    }


    private PmsBoxTrace createPmsBoxTrace(StmStoreInfo storeInfo, OmsOrder omsOrder, Date date) {
        PmsBoxTrace PmsBoxTrace = new PmsBoxTrace();
        PmsBoxTrace.setFstockname(storeInfo.getName());
        PmsBoxTrace.setFstockaddress(storeInfo.getProvince() + storeInfo.getCity() + storeInfo.getDistrict() + storeInfo.getAddress());
        PmsBoxTrace.setFstockoutbillno(omsOrder.getId());
        PmsBoxTrace.setFstockoutdate(DateUtil.formatDateTime(date));
        //经销商名称n
        PmsBoxTrace.setFcustomername(omsOrder.getCompanyName());
        //经销商编码
        PmsBoxTrace.setFcustomernumber(omsOrder.getCompanyCode());
        //经销商授权区域
        PmsBoxTrace.setFcustomerauthregion("无");
        //收货人
        PmsBoxTrace.setFreceiver(omsOrder.getReceiverName());
        //收货地址
        PmsBoxTrace.setFreceiveaddress(omsOrder.getReceiverProvince() + omsOrder.getReceiverCity() + omsOrder.getReceiverRegion() + omsOrder.getReceiverDetailAddress());
        PmsBoxTrace.setFdoporderid(omsOrder.getId());
        //销售订单提交时间
        PmsBoxTrace.setFdopordersubmitdate(DateUtil.formatDateTime(omsOrder.getCreateTime()));
        PmsBoxTrace.setFdoporderbillno(omsOrder.getId());
        //物流公司名称，这里拿不到
        PmsBoxTrace.setFlogisticscompanyname("无");

        return PmsBoxTrace;
    }
}
